#ifndef _ENEMIES_H
#define _ENEMIES_H

#include "../includes.h"

//{ ********** Enemy class **********

class cEnemy: public cSprite
{
    public:

        // enemy bullet class is nested in enemy class, because it will only be used here.
        class cEnemyBullet: public cSprite
        {
            public:

                void fire(const cEnemy* enemy);

                cEnemyBullet(std::string pImage, int pImageID, int pSpriteID, const cEnemy* enemy);
                cEnemyBullet(const cEnemyBullet& enemyBullet);
                ~cEnemyBullet(void);
        };

        // class variables
        vector<cEnemy::cEnemyBullet> bullets;
        unsigned int lastFired;
        unsigned short nextBullet, totalBullets;

        enum eEnemyType{
            pirate = 0,
            seeker = 1,
            kamikaze = 2,
            screamer = 3,
            helicopter = 4,
            machineGun = 5,
            spider = 6}
        enemyType;

        // class functions
        virtual void update(void);

        // constructor and destructor prototypes
        cEnemy(std::string pImage, int pImageID, int pSpriteID, eEnemyType pEnemyType, int pX, int pY, float pAngle);
        cEnemy(const cEnemy& prev);
        ~cEnemy(void);
};

cEnemy::cEnemy(std::string pImage, int pImageID, int pSpriteID, eEnemyType pEnemyType, int pX, int pY, float pAngle)
{
    // set up main sprite attributes
    image = pImage; imageID = pImageID; spriteID = pSpriteID; enemyType = pEnemyType;
    X = pX; Y = pY; angle = pAngle; speed = -200.0f; copy = false; lastFired = dbTimer();
    nextBullet = 0; totalBullets = 4;

    // if image doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    //make sprite
    dbSprite(spriteID, (int)X, (int)Y, imageID);

    for (unsigned short x = 0; x < totalBullets; x++)
        bullets.push_back(cEnemyBullet("media/cannonBall.png", 5, findFreeSprite(), this));

    // get the middle of the sprite and offset it there, sprite priority is 1, so it gets drawn under aim reticle, but above antying in background
    midX = dbImageWidth(imageID) / 2; midY = dbImageHeight(imageID) / 2;
    dbOffsetSprite(spriteID, midX, midY); dbSetSpritePriority(spriteID, 1);
    hidden = false;
    //dbHideSprite(spriteID); hidden = true;
}

cEnemy::cEnemy(const cEnemy& prev)
{
    // copy over regular stuff
    image = prev.image; imageID = prev.imageID; spriteID = prev.spriteID;
    X = prev.X; Y = prev.Y; angle = prev.angle; speed = prev.speed;
    midX = prev.midX; midY = prev.midY; enemyType = prev.enemyType;
    hidden = prev.hidden; lastFired = prev.lastFired; nextBullet = prev.nextBullet;
    totalBullets = prev.totalBullets;

    bullets = prev.bullets;

    // set current copy to false, and old copy to true
    copy = false; prev.copy = true;

    // if image doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    // re-render teh sprite to where it was
    dbSprite(spriteID, (int)X, (int)Y, imageID);
}

cEnemy::~cEnemy(void)
{
    // if the iteration is being destroyed, not copied, then delete the sprite.
    if (copy==false)
    {
        if (dbIsSprite(spriteID))
            dbDeleteSprite(spriteID);
    }
}

void cEnemy::update(void)
{
    // if the sprite isn't visible, don't bother updating
    if (!onScreen())
        return;

    // determine enemy type, and update based on that
    switch(enemyType)
    {
        case pirate:

            dbRotateSprite(spriteID, angle);
            X += timerBased(speed * dbCos(angle + 90.0f));
            Y += timerBased(speed * dbSin(90.0f - angle));

            dbSprite(spriteID, (int)X, (int)Y, imageID);

            if(dbTimer() - lastFired >= 500)
            {
                lastFired = dbTimer();
                bullets[nextBullet].fire(this);

                if (nextBullet == totalBullets - 1)
                    nextBullet = 0;
                else
                    ++nextBullet;
            }

            break;

        case seeker:
            break;

        case kamikaze:
            break;

        case screamer:
            break;

        case helicopter:
            break;

        case machineGun:
            break;

        case spider:
            break;

        default:
            break;
    }

    // update enemy bullets
    for (unsigned short x = 0; x < totalBullets; x++)
        bullets[x].update();

    return;
}

//} ********** Enemy class **********

//{ ********** enemy bullets class **********

cEnemy::cEnemyBullet::cEnemyBullet(std::string pImage, int pImageID, int pSpriteID, const cEnemy* enemy)
{
    // set up sprite variables
    image = pImage; imageID = pImageID; spriteID = pSpriteID;
    X = enemy->X; Y = enemy->Y; angle = enemy->angle;
    speed = -1000.0f; copy = false;

    // if imagenum doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    //make sprite at player location
    dbSprite(spriteID, (int)X, (int)Y, imageID);

    // get the middle of the sprite and offset it there
    midX = dbImageWidth(imageID) / 2; midY = dbImageHeight(imageID) / 2;
    dbOffsetSprite(spriteID, midX, midY);

    // hide the sprite, it will be shown when fired
    dbHideSprite(spriteID); hidden = true;
}

cEnemy::cEnemyBullet::cEnemyBullet(const cEnemyBullet& b)
{
    // set up sprite variables
    image = b.image; imageID = b.imageID; spriteID = b.spriteID;
    X = b.X; Y = b.Y; midX = b.midX; midY = b.midY; angle = b.angle; speed = b.speed;
    hidden = b.hidden;

    //set current copy to false, and old copy to true, since copy construct only gets called when resizing a vector
    copy = false; b.copy = true;

    // if imagenum doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    // set sprite to old sprite location, and rotate to old angle
    dbSprite(spriteID, (int)X, (int)Y, imageID);
    dbRotateSprite(spriteID, angle);
}

cEnemy::cEnemyBullet::~cEnemyBullet(void)
{
    // if the iteration is being destroyed, not copied, then delete the sprite.
    if (copy==false)
    {
        if (dbIsSprite(spriteID))
            dbDeleteSprite(spriteID);
    }
}

void cEnemy::cEnemyBullet::fire(const cEnemy* enemy)
{
    // start the bullet where the enemy ship is
    X = enemy->X; Y = enemy->Y; angle = enemy->angle;

    dbSprite(spriteID, X, Y, imageID);
    if(hidden)
    {
        dbShowSprite(spriteID); hidden = false;
    }

    return;
}

//} ********** enemy bullets class **********

#endif
